package com.wejoy.video.middle.station.data.service.system.impl;

import com.wejoy.video.middle.station.data.domain.system.SysResource;
import com.wejoy.video.middle.station.data.domain.system.SysRole;
import com.wejoy.video.middle.station.data.domain.system.SysRoleResource;
import com.wejoy.video.middle.station.data.enums.dict.EnumStatus;
import com.wejoy.video.middle.station.data.enums.dict.EnumSysResourceType;
import com.wejoy.video.middle.station.data.exception.BusinessException;
import com.wejoy.video.middle.station.data.mapper.system.ISysRoleResourceMapper;
import com.wejoy.video.middle.station.data.service.common.IIdWorkerService;
import com.wejoy.video.middle.station.data.service.system.ISysResourceService;
import com.wejoy.video.middle.station.data.service.system.ISysRoleResourceService;
import com.wejoy.video.middle.station.data.service.system.ISysRoleService;
import com.wejoy.video.middle.station.data.util.WJAssert;
import com.wejoy.video.middle.station.data.vo.system.SysRoleResourceVO;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 系统-角色权限关联表
 *
 * @author admin
 * @date 2021年10月19日 15:06:41
 */
@Service
public class SysRoleResourceServiceImpl implements ISysRoleResourceService {
    @Autowired
    private ISysRoleResourceMapper sysRoleResourceMapper;
    @Autowired
    private IIdWorkerService idWorkerService;
    @Autowired
    private ISysResourceService sysResourceService;
    @Autowired
    private ISysRoleService sysRoleService;

    @Override
    public void save(SysRoleResource req, String operator) {
        req.setOperator(operator);
        if (null == req.getId()) {
            insertSelective(req);
        } else {
            updateSelectiveById(req);
        }
    }

    @Override
    public int insertSelective(SysRoleResource req) {
        req.setId(idWorkerService.getNextId());
        req.setStatus(EnumStatus.NEW.getCode());
        checkStringLength(req, false);
        return sysRoleResourceMapper.insertSelective(req);
    }

    @Override
    public int updateSelectiveById(SysRoleResource sysRoleResource) {
        WJAssert.notNull(sysRoleResource, "入参对象不能为空");
        WJAssert.notNull(sysRoleResource.getId(), "id参数错误");
        SysRoleResource where = new SysRoleResource();
        where.setId(sysRoleResource.getId());
        return sysRoleResourceMapper.updateSelective(sysRoleResource, where);
    }

    @Override
    public int getCount(SysRoleResource sysRoleResource) {
        checkStringLength(sysRoleResource, true);
        return sysRoleResourceMapper.getCount(sysRoleResource);
    }

    @Override
    public SysRoleResource getOneById(Long id) {
        WJAssert.notNull(id, "id参数错误");
        SysRoleResource where = new SysRoleResource();
        where.setId(id);
        return sysRoleResourceMapper.getOne(where);
    }

    @Override
    public List<SysRoleResource> getList(SysRoleResource sysRoleResource) {
        checkStringLength(sysRoleResource, true);
        return sysRoleResourceMapper.getList(sysRoleResource);
    }

    @Override
    public List<SysRoleResource> getPageList(SysRoleResource sysRoleResource) {
        checkStringLength(sysRoleResource, true);
        return sysRoleResourceMapper.getPageList(sysRoleResource);
    }

    @Override
    public void audit(Long id, String operator) {
        SysRoleResource req = new SysRoleResource();
        req.setId(id);
        req.setOperator(operator);
        req.setStatus(EnumStatus.AUDIT.getCode());
        updateSelectiveById(req);
    }

    @Override
    public void unaudit(Long id, String operator) {
        SysRoleResource req = new SysRoleResource();
        req.setId(id);
        req.setOperator(operator);
        req.setStatus(EnumStatus.NEW.getCode());
        updateSelectiveById(req);
    }

    @Override
    public void delete(Long id, String operator) {
        SysRoleResource req = new SysRoleResource();
        req.setId(id);
        req.setOperator(operator);
        req.setStatus(EnumStatus.DEL.getCode());
        updateSelectiveById(req);
    }

    /**
     * 构建用户资源菜单及资源标识
     *
     * @param sysUserRoleIdList
     * @param sysUserResourceList
     * @param sysResourceIdentityList
     */
    @Override
    public void buildUserResourceListAndIdentityList(List<SysRole> sysUserRoleIdList, List<SysResource> sysUserResourceList,
                                                     List<String> sysResourceIdentityList) {
        if (CollectionUtils.isEmpty(sysUserRoleIdList)) {
            return;
        }
        List<Long> roleIds = sysUserRoleIdList.stream().map(SysRole::getId).collect(Collectors.toList());
        List<SysRoleResource> list = sysRoleResourceMapper.getListBySysRoleIdIn(roleIds);
        if (CollectionUtils.isEmpty(list)) {
            return;
        }
        List<Long> resourceIdList = list.stream().map(SysRoleResource::getSysResourceId).distinct().collect(Collectors.toList());

        SysResource sysResourceWhere = new SysResource();
        sysResourceWhere.setStatus(EnumStatus.NEW.getCode());
        sysResourceWhere.setIdsList(resourceIdList);
        List<SysResource> sysResourcesList = sysResourceService.getList(sysResourceWhere);
        if (CollectionUtils.isEmpty(sysResourcesList)) {
            return;
        }
        //用户所拥有资源标识
        List<String> resourceIdentityList = sysResourcesList.stream().map(SysResource::getIdentity).collect(Collectors.toList());
        //目录资源集合
        List<SysResource> allCatalogueResourceList = sysResourcesList.stream().filter(item -> {
            return EnumSysResourceType.CATALOGUE.getCode().equals(item.getType());
        }).sorted(Comparator.comparing(SysResource::getSort)).collect(Collectors.toList());
        //菜单资源集合
        List<SysResource> allMenuResourceList = sysResourcesList.stream().filter(item -> {
            return EnumSysResourceType.MENU.getCode().equals(item.getType());
        }).collect(Collectors.toList());
        //用户所拥有目录菜单资源盖楼
        List<SysResource> userResourceList = allCatalogueResourceList.stream()
                .peek(item -> {
                    List<SysResource> childrenList = allMenuResourceList.stream().filter(childrenItem -> {
                        return item.getId().toString().equals(childrenItem.getParentId());
                    }).sorted(Comparator.comparing(SysResource::getSort)).collect(Collectors.toList());
                    item.setChildren(childrenList);
                }).collect(Collectors.toList());
        sysUserResourceList.addAll(userResourceList);
        sysResourceIdentityList.addAll(resourceIdentityList);
    }

    /**
     * 添加角色资源
     *
     * @param roleResourceVO
     * @param roleResourceIdReq
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addResource(SysRoleResourceVO roleResourceVO, String roleResourceIdReq) {
        List<Long> newResourcesList = roleResourceVO.getResourcesIds();
        if (null == roleResourceVO.getRoleId()) {
            return;
        }
        SysRole sysRoleDB = sysRoleService.getOneById(roleResourceVO.getRoleId());
        if (sysRoleDB == null) {
            throw new BusinessException("不存的角色!");
        }
        sysRoleResourceMapper.deleteByRoleId(roleResourceVO.getRoleId());
        if (CollectionUtils.isEmpty(newResourcesList)) {
            return;
        }
        List<SysRoleResource> list = newResourcesList.parallelStream().map(item -> {
            SysRoleResource req = new SysRoleResource();
            req.setOperator(roleResourceIdReq);
            req.setSysResourceId(item);
            req.setSysRoleId(roleResourceVO.getRoleId());
            req.setId(idWorkerService.getNextId());
            req.setStatus(EnumStatus.NEW.getCode());
            return req;
        }).collect(Collectors.toList());
        sysRoleResourceMapper.batchInsert(list);
    }

    /**
     * 获取角色所拥有权限 el-tree树默认勾选
     * 1.获取当前角色所拥有所有权限菜单
     * 2.分别获取当前角色所拥有所有权限菜单中的目录、菜单、按钮集合
     * 3.过滤当前角色菜单中是否所有按钮权限都拥有，是返回当前菜单ID 否 不返回（决定当前菜单树下面的所有子节点是否全勾选）
     * 4.过滤当前角色目录中是否所有菜单权限都拥有，（使用步骤三过滤出来的菜单集合进行判断）是返回当前目录ID 否 不返回（决定当前菜单树下面的所有子节点是否全勾选）
     * 5.返回过滤后的目录、菜单、按钮集合（用与默认勾选）与无过滤的集合（防止不更改直接提交）
     *
     * @param roleId
     * @return
     */
    @Override
    public Map<String, Object> getResourcesIdListByRoleId(Long roleId) {
        Map<String, Object> resultMap = new HashMap<>(2);
        resultMap.put("checkedTreeList", new ArrayList<>());
        resultMap.put("treeList", new ArrayList<>());

        List<Long> resultList = new ArrayList<>();
        SysRoleResource req = new SysRoleResource();
        req.setSysRoleId(roleId);
        //查询出这个角色的所有资源
        List<Long> resourceIdList = getList(req).stream().map(SysRoleResource::getSysResourceId).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(resourceIdList)) {
            return resultMap;
        }

        SysResource sysResourceWhere = new SysResource();
        sysResourceWhere.setStatus(EnumStatus.NEW.getCode());
        sysResourceWhere.setIdsList(resourceIdList);
        List<SysResource> sysResourcesList = sysResourceService.getList(sysResourceWhere);
        if (CollectionUtils.isEmpty(sysResourcesList)) {
            return resultMap;
        }
        //用户所拥有目录资源集合
        List<Long> allCatalogueResourceIdList = sysResourcesList.stream().filter(item -> {
            return EnumSysResourceType.CATALOGUE.getCode().equals(item.getType());
        }).map(SysResource::getId).collect(Collectors.toList());

        //用户所拥有菜单资源集合
        List<SysResource> allMenuResourceIdList = sysResourcesList.stream().filter(item -> {
            return EnumSysResourceType.MENU.getCode().equals(item.getType());
        }).collect(Collectors.toList());

        //用户所拥有按钮资源集合
        List<SysResource> allButtonResourceIdList = sysResourcesList.stream().filter(item -> {
            return EnumSysResourceType.BUTTON.getCode().equals(item.getType());
        }).collect(Collectors.toList());


        SysResource srWhere = new SysResource();
        srWhere.setStatus(EnumStatus.NEW.getCode());
        List<SysResource> resourceAllListDB = sysResourceService.getList(srWhere);


        //过滤后的结果菜单
        List<SysResource> menuResourceIdListResult = allMenuResourceIdList.stream()
                .filter(item -> {
                    return isHasAllChildren(allButtonResourceIdList, resourceAllListDB, EnumSysResourceType.BUTTON.getCode(), item.getId().toString());
                }).collect(Collectors.toList());

        //过滤后的结果目录
        List<Long> catalogueResourceIdListResult = allCatalogueResourceIdList.stream()
                .filter(item -> {
                    return isHasAllChildren(menuResourceIdListResult, resourceAllListDB, EnumSysResourceType.MENU.getCode(), item.toString());
                }).collect(Collectors.toList());
        List<Long> buttonIdList = allButtonResourceIdList.stream().map(SysResource::getId).collect(Collectors.toList());
        List<Long> menuIdList = menuResourceIdListResult.stream().map(SysResource::getId).collect(Collectors.toList());
        resultList.addAll(catalogueResourceIdListResult);
        resultList.addAll(menuIdList);
        resultList.addAll(buttonIdList);

        resultMap.put("checkedTreeList", resultList);
        resultMap.put("treeList", resourceIdList);

        return resultMap;
    }

    /**
     * 菜单是否包含所有子类
     *
     * @param resourceIdList
     * @param type
     * @param resourceId
     * @return
     */
    private boolean isHasAllChildren(List<SysResource> resourceIdList, List<SysResource> resourceAllListDB, Integer type, String resourceId) {
        //得到当前类型的所有对应子节点
        List<Long> idList = resourceIdList.stream().filter(item -> {
            return item.getParentId().equals(resourceId);
        }).map(SysResource::getId).collect(Collectors.toList());

        List<Long> idListDB = resourceAllListDB.stream()
                .filter(item -> {
                    return item.getParentId().equals(resourceId) && item.getType().equals(type);
                }).map(SysResource::getId).collect(Collectors.toList());

        if (CollectionUtils.isEmpty(idListDB)) {
            return true;
        }
        return idList.size() == idListDB.size();
    }

    /**
     * 参数校验注解默认使用的方法
     */
    private void checkStringLength(SysRoleResource sysRoleResource, boolean nullAble) {
        WJAssert.notNull(sysRoleResource, "入参对象不能为空");
        WJAssert.limitMaxLength(sysRoleResource.getOperator(), true, 255, "操作人不合法!");
        WJAssert.limitMaxLength(sysRoleResource.getRemark(), true, 255, "备注不合法!");
    }
}
